﻿using LxBasic;

namespace LxCore
{
    public class EquationWithTransTerm : EquationBase
    {
        public EquationTransTerm TransData;
        public void SetZone_TransTerm(bool isEnable, IField<double> Trans, IField<double> density)//isEnable其实没必要传，主要是提醒，在不启用时Trans和density只传入null即可
        {
            if (isEnable)
            {
                if (TransData == null)
                {
                    TransData = new EquationTransTerm();
                    TransData.CheckCreate(this);
                }
                TransData.SetTrans(Trans, density);
            }
            else
            {
                TransData = null;
            }
        }
        public override void Reuse(ZoneHead oldOne)
        {
            base.Reuse(oldOne);
            if (oldOne is EquationWithTransTerm o && o.TransData != null)
            {
                TransData = o.TransData;
            }
        }
        public override bool IsInitialized => base.IsInitialized && (TransData == null || TransData.IsInitialized);
        public override void Initialize()
        {
            base.Initialize();
            TransData?.Initialize();
        }
        public class EquationTransTerm : TransDataBase
        {
            public IField<double> Trans;
            public IField<double> Density;

            public double[] RhoTransPhi_o;
            public double[] RhoTransPhi_oo;
            public TransientDataStates TransientDataState = TransientDataStates.None;

            protected EquationWithTransTerm Matrix;
            public void CheckCreate(EquationWithTransTerm Matrix)
            {
                this.Matrix = Matrix;
                CheckCreator.ArrayStrict(ref RhoTransPhi_o, Matrix.Zone.Inner.CellIdx.GetCount());
                if (IsSecondOrder)
                {
                    CheckCreator.ArrayStrict(ref RhoTransPhi_oo, Matrix.Zone.Inner.CellIdx.GetCount());
                }
                else
                {
                    RhoTransPhi_oo = null;
                }
            }
            public void SetTrans(IField<double> Trans, IField<double> density)
            {
                this.Trans = Trans;
                this.Density = density;
            }

            public override bool IsInitialized => TransientDataState != TransientDataStates.None;
            private (int i1, int endp1, FvInnCell[] InnCells, double[] XInn, double[] ADiag, double[] B, ICellVarArr<double> tran, ICellVarArr<double> den) getMatrixData(ThreadInfo threadInfo)
            {
                (int i1, int endp1) = Matrix.Zone.Inner.CellIdx.Split(threadInfo);
                return (i1, endp1, Matrix.Zone.InnCells, Matrix.InnX, Matrix.ADiag, Matrix.B, Trans.GetCellVarArr(Matrix.Zone.Inner), Density.GetCellVarArr(Matrix.Zone.Inner));
            }
            private void SaveOldValue(ThreadInfo threadInfo)
            {
                (int i1, int endp1, FvInnCell[] InnCells, double[] XInn, double[] ADiag, double[] B, ICellVarArr<double> tran, ICellVarArr<double> den) = getMatrixData(threadInfo);
                var rhoTransPhi = RhoTransPhi_o;
                for (; i1 < endp1; i1++)
                {
                    rhoTransPhi[i1] = tran.GetCellVar(i1) * den.GetCellVar(i1) * XInn[i1];//* Cells[i1].Volumn 
                }
            }
            public override void SaveOldValue()
            {
                if (IsSecondOrder)
                {
                    LxTool.Exchange(ref RhoTransPhi_o, ref RhoTransPhi_oo);
                }
                MultiThreads.RunParallelTask(SaveOldValue);
                if (IsSecondOrder)
                {
                    switch (TransientDataState)
                    {
                        case TransientDataStates.None: TransientDataState = TransientDataStates.Only_o; break;
                        case TransientDataStates.Only_o: TransientDataState = TransientDataStates.Both_o_oo; break;
                        default: break;
                    }
                }
                else
                {
                    switch (TransientDataState)
                    {
                        case TransientDataStates.None: TransientDataState = TransientDataStates.Only_o; break;
                        default: break;
                    }
                }
            }
            public override void FormAb_ImplicitTrans(ThreadInfo threadInfo)
            {
                (int i1, int endp1, FvInnCell[] InnCells, double[] XInn, double[] ADiag, double[] B, ICellVarArr<double> tran, ICellVarArr<double> den) = getMatrixData(threadInfo);
                if (IsSecondOrder && TransientDataState == TransientDataStates.Both_o_oo)
                {
                    (double f, double fo, double foo) = GetFactor_2ndOrder();
                    for (; i1 < endp1; i1++)
                    {
                        double vol = InnCells[i1].Volumn;
                        B[i1] -= (fo * RhoTransPhi_o[i1] + foo * RhoTransPhi_oo[i1]) * vol;
                        ADiag[i1] += f * tran.GetCellVar(i1) * den.GetCellVar(i1) * vol;
                    }
                }
                else
                {
                    double f = GetFactor_1stOrder();
                    for (; i1 < endp1; i1++)
                    {
                        double vol = InnCells[i1].Volumn;
                        B[i1] += f * RhoTransPhi_o[i1] * vol;
                        ADiag[i1] += f * tran.GetCellVar(i1) * den.GetCellVar(i1) * vol;
                    }
                }
            }
            public override void FormAb_ExplicitTrans(ThreadInfo threadInfo)
            {
                (int i1, int endp1, FvInnCell[] InnCells, double[] XInn, double[] ADiag, double[] B, ICellVarArr<double> tran, ICellVarArr<double> den) = getMatrixData(threadInfo);
                if (IsSecondOrder && TransientDataState == TransientDataStates.Both_o_oo)
                {
                    (double f, double fo, double foo) = GetFactor_2ndOrder();
                    for (; i1 < endp1; i1++)
                    {
                        double vol = InnCells[i1].Volumn;
                        B[i1] += -ADiag[i1] * XInn[i1] - (fo * RhoTransPhi_o[i1] + foo * RhoTransPhi_oo[i1]) * vol;//-calALUProductValue(ref cells[i1], x),显示求解的时候会做，这里不做
                        ADiag[i1] = f * tran.GetCellVar(i1) * den.GetCellVar(i1) * vol;
                    }
                }
                else
                {
                    double f = GetFactor_1stOrder();
                    for (; i1 < endp1; i1++)
                    {
                        double vol = InnCells[i1].Volumn;
                        B[i1] += -ADiag[i1] * XInn[i1] + f * RhoTransPhi_o[i1] * vol; //-calALUProductValue(ref cells[i1], x),显示求解的时候会做，这里不做
                        ADiag[i1] = f * tran.GetCellVar(i1) * den.GetCellVar(i1) * vol;//beforePhiO和beforePhi互为相反数，因此不用获取
                    }
                }
            }
            public override void Initialize()
            {
                if (IsInitialized) return;
                SaveOldValue();
                TransientDataState = TransientDataStates.Only_o;
            }
        }
    }
}
